package com.chensi.admin.shop.service.impl;

import com.chensi.admin.shop.common.BaseErrorCode;
import com.chensi.admin.shop.domain.GoodsUser;
import com.chensi.admin.shop.dto.GoodsUserDTO;
import com.chensi.admin.shop.dto.mapper.GoodsUserMapper;
import com.chensi.admin.shop.service.GoodsUserService;
import com.chensi.admin.shop.util.CommonUtil;
import com.chensi.admin.shop.util.SpecificationUtil;
import com.chensi.admin.shop.dao.GoodsUserRepository;
import com.chensi.admin.shop.exception.BaseException;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author si.chen
 * @date 2019/7/16 9:49
 */
@Service
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class GoodsUserServiceImpl implements GoodsUserService {

    private final GoodsUserRepository goodsUserRepository;

    private final GoodsUserMapper goodsUserMapper;

    @Autowired
    public GoodsUserServiceImpl(GoodsUserRepository goodsUserRepository, GoodsUserMapper goodsUserMapper) {
        this.goodsUserRepository = goodsUserRepository;
        this.goodsUserMapper = goodsUserMapper;
    }

    @Override
    public List<GoodsUserDTO> list(GoodsUser entity) {
        Sort sort = new Sort(Sort.Direction.ASC, "id");
        return goodsUserRepository.findAll(this.getSpecification(entity), sort).stream().map(goodsUserMapper::toDTO)
                .collect(Collectors.toList());
    }

    @Override
    public Page<GoodsUserDTO> page(GoodsUser entity) {
        Sort sort = new Sort(Sort.Direction.ASC, "id");
        Pageable pageable = PageRequest.of(entity.getPageParam().getPageNo(), entity.getPageParam().getPageSize(), sort);
        return goodsUserRepository.findAll(this.getSpecification(entity), pageable).map(goodsUserMapper::toDTO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void create(GoodsUser entity) throws BaseException {
        this.checkUniqueForCreate(entity);
        goodsUserRepository.save(entity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(String id) {
        goodsUserRepository.deleteById(id);
    }

    private void checkUniqueForCreate(GoodsUser entity) throws BaseException {
        //联合主键唯一约束
        if (StringUtils.isNotBlank(entity.getUserId()) && entity.getGoods() != null
                && StringUtils.isNotBlank(entity.getGoods().getId())) {
            GoodsUser param = new GoodsUser();
            param.setUserId(entity.getUserId());
            param.setGoods(entity.getGoods());
            if (CommonUtil.isNotEmptyList(this.list(param))) {
                throw new BaseException(BaseErrorCode.IS_USED);
            }
        }
    }

    @SuppressWarnings("Duplicates")
    private Specification<GoodsUser> getSpecification(GoodsUser entity) {
        return (root, query, cb) -> {
            List<Predicate> list = new ArrayList<>();
            SpecificationUtil.baseSpecification(root, cb, list, entity);
            if (StringUtils.isNotBlank(entity.getUserId())) {
                Predicate predicate = cb.equal(root.get("userId"), entity.getUserId().trim());
                list.add(predicate);
            }
            if (entity.getGoods() != null && StringUtils.isNotBlank(entity.getGoods().getId())) {
                Predicate predicate = cb.equal(root.get("goods").get("id"), entity.getGoods().getId().trim());
                list.add(predicate);
            }
            query.where(list.toArray(new Predicate[0]));
            return query.getRestriction();
        };
    }
}
